// Copyright (C) 1953-2022 NUDT
// Verilog module name - token_bucket_algorithm
// Version: V4.0.0.20220526
// Created:
//         by - fenglin 
////////////////////////////////////////////////////////////////////////////
// Description:
//         
///////////////////////////////////////////////////////////////////////////

`timescale 1ns/1ps

module token_bucket_algorithm
#(
    parameter clk_period = {8'd8,41'h0}//8ns
)
(
//i_clk & rst
input	wire			i_clk,
input	wire			i_rst_n,

//receive
(*MARK_DEBUG="true"*)input	wire     [87:0] iv_desp,     
(*MARK_DEBUG="true"*)input	wire            i_desp_wr,

//receive 
input	wire     [15:0] iv_add_tokens_num_perround,       // =100*8ns(per cycle)*(rate(bps)/8)*(10^-9)= rate/(10Mbps);dd number of token per 800ns(100 cycles); the minimum committed information rate 10Mbps is allowed.
input	wire     [15:0] iv_token_bucket_size,
//transmit
(*MARK_DEBUG="true"*)output	reg      [87:0]  ov_desp  ,
(*MARK_DEBUG="true"*)output  reg              o_desp_wr

);
//token bucken parameter
reg  [15:0]   rv_remaining_tokens;         //remaining tokens
reg  [15:0]   rv_consume_tokens;         //consume tokens,1Byte consumes 1 token.
reg  [31:0]   rv_ns_cnt;    //timer of token bucken
//************************************************************
//                   Consume tokens
//************************************************************
always@(posedge i_clk or negedge i_rst_n) begin
    if(i_rst_n == 1'b0) begin
        ov_desp           <= 88'b0;
        o_desp_wr         <= 1'b0 ;
    
        rv_consume_tokens <= 16'd0;	
    end
    else begin
		if(i_desp_wr)begin
            if((iv_desp[2:0] == 3'd3) || (iv_desp[2:0] == 3'd4))begin
                if(rv_remaining_tokens >= (iv_desp[27:17] + 11'd4))begin//pkt_length + 4B CRC.    
                    rv_consume_tokens <= {5'b0,iv_desp[27:17] + 11'd4};
                    
                    ov_desp           <= iv_desp;
                    o_desp_wr         <= 1'b1 ;
                end
                else begin
                    rv_consume_tokens       <= 16'd0;
                    ov_desp[86:0]           <= iv_desp[86:0];
                    ov_desp[87]             <= 1'b1;//discard
                    o_desp_wr               <= 1'b1 ;
                end
            end
            else begin
                rv_consume_tokens <= 16'b0;
                
                ov_desp           <= iv_desp;
                o_desp_wr         <= 1'b1 ;            
            end
        end
        else begin
            ov_desp           <= 88'b0;
            o_desp_wr         <= 1'b0 ;
        
            rv_consume_tokens <= 16'd0;	        
        end
    end
end 
//************************************************************
//                    Count token
//************************************************************
always@(posedge i_clk or negedge i_rst_n) begin
    if(i_rst_n == 1'b0) begin
        rv_remaining_tokens <= 16'd0;
		rv_ns_cnt           <= 32'd0;
    end
    else begin
	    if(rv_ns_cnt + clk_period[48:25] >= {16'd8000,16'b0})begin
		    rv_ns_cnt <= rv_ns_cnt + clk_period[48:25] - {16'd8000,16'b0};
			if(rv_remaining_tokens - rv_consume_tokens <= iv_token_bucket_size -  iv_add_tokens_num_perround)begin
			    rv_remaining_tokens <= rv_remaining_tokens + iv_add_tokens_num_perround - rv_consume_tokens;
			end
			else begin
			    rv_remaining_tokens <= iv_token_bucket_size;
			end
		end
		else begin
		    rv_ns_cnt <= rv_ns_cnt + clk_period[48:25];
			rv_remaining_tokens <= rv_remaining_tokens - rv_consume_tokens;
		end
    end
end        
endmodule